<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:replace="~{commons/commons::head}"></div>

<body>
<!-- 顶部导航栏 -->
<div th:replace="~{commons/commons::topbar}"></div>

<div class="container-fluid">
    <div class="row">
        <!-- 侧边栏 -->
        <div th:replace="~{commons/commons::siderbar(active='passwordreset.html')}"></div>

        <main role="main" class="col-md-10 offset-md-2 pt-3 main">
            <div class="card">
                <div class="card-header py-1">
                    <div class="vul_header">
                        <span>密码重置漏洞</span>
                        <span class="header_link">
                            <a class="btn btn-sm btn-primary" href="#">漏洞案例</a>
                            <a class="btn btn-sm btn-primary" href="#">wiki</a>
                        </span>
                    </div>
                </div>
                <div class="card-body">
                    <ul class="nav nav-tabs">
                        <li class="nav-item">
                            <a class="nav-link active" data-toggle="tab" href="#vulDescription">
                                漏洞描述</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" data-toggle="tab" href="#secureCoding"> 安全编码</a>
                        </li>
                    </ul>
                    <div class="tab-content">
                        <div class="tab-pane active" id="vulDescription">
                            <div class="alert alert-desc"><i class="lnr lnr-alarm"></i>
                                密码重置漏洞在逻辑漏洞中相当常见，并且属于严重的安全漏洞之一。攻击者利用这种漏洞可以在未经授权的情况下，通过构造恶意的重置密码链接或者通过暴力破解验证码等手段，直接重置其他用户的密码。一旦攻击者成功地重置了密码，他们可以轻松地获取对应用户的账户权限，并进一步利用该账户访问应用系统，造成重大安全风险和数据泄露。
                            </div>
                        </div>
                        <div class="tab-pane fade" id="secureCoding">
                            <div class="alert alert-desc">
                                服务器端验证：在接收到密码重置请求时，应该在服务器端进行验证。验证过程应包括对用户身份的验证、密码重置链接的有效性验证以及验证码的正确性验证等。<br>
                                验证码有效性：验证码应该由后端生成并发送至用户邮箱或手机，此外，验证码应该有一定的有效期限，最好6位数字，并在使用几次后失效，以防止被恶意利用。<br>
                                安全链接：密码重置链接应该采用安全的方式生成，并包含足够的随机性和唯一性，以防止被猜测或者暴力破解。同时，链接应该具有一定的时效性，一旦过期就不能再被使用。<br>
                                安全设计：在设计密码重置流程时，校验密码时应该加防暴力破解机制，如图形验证码、失效时间等。
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="box-float">
                <div class="float1">
                    <div class="card">
                        <div class="card-header py-1"><span class="lnr lnr-bug"> 漏洞场景 - 验证码前端回显</span></div>
                        <div class="card-body">
                            <form id="smsForm" onsubmit="resetPassword(); return false;">
                                <div class="form-group row">
                                    <label for="phone" class="col-sm-2 col-form-label">手机号：</label>
                                    <div class="col-sm-10">
                                        <input type="text" class="form-control" id="phone" name="phone" required>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <label for="authCode" class="col-sm-2 col-form-label">验证码：</label>
                                    <div class="col-sm-10">
                                        <div class="input-group">
                                            <input type="text" class="form-control" id="authCode" name="authCode"
                                                   placeholder="请输入6位数验证码"
                                                   required>
                                            <div class="input-group-append">
                                                <button class="btn btn-sm btn-primary" type="button" id="getcode"
                                                        onclick="sendSms()">获取验证码
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <label for="newPassword" class="col-sm-2 col-form-label">新密码：</label>
                                    <div class="col-sm-10">
                                        <input type="password" class="form-control" id="newPassword" name="newPassword"
                                               required>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <div class="col-sm-10 offset-sm-2">
                                        <button type="submit" class="btn btn-danger form-control">重置密码</button>
                                    </div>
                                </div>
                            </form>

                        </div>
                    </div>

                    <textarea class="form-control" id="code1">
public Map<String, String> resetPassword(@RequestParam("mobile") String mobile, HttpServletRequest request) {
    Map<String, String> response = new HashMap< >();
    String authCode = generateRandomCode();

    // 发送短信代码
    ...

    // 漏洞点：返回验证码到前端
    response.put("success", "true");
    response.put("mobile", mobile);
    response.put("authCode", authCode);
    return response;
}
          </textarea><br><br>
                </div>

                <div class="float2">
                    <div class="card">
                        <div class="card-header py-1"><span class="lnr lnr-bug"> 漏洞场景 - 验证码可爆破</span></div>
                        <div class="card-body">
                            <form id="smsForm2" onsubmit="resetPassword2(); return false;">
                                <div class="form-group row">
                                    <label for="phone" class="col-sm-2 col-form-label">手机号：</label>
                                    <div class="col-sm-10">
                                        <input type="text" class="form-control" id="phone2" name="phone2" required>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <label for="authCode" class="col-sm-2 col-form-label">验证码：</label>
                                    <div class="col-sm-10">
                                        <div class="input-group">
                                            <input type="text" class="form-control" id="authCode2" name="authCode2"
                                                   placeholder="请输入4位数验证码"
                                                   required>
                                            <div class="input-group-append">
                                                <button class="btn btn-sm btn-primary" type="button" id="getcode2"
                                                        onclick="sendSms2()">获取验证码
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <label for="newPassword" class="col-sm-2 col-form-label">新密码：</label>
                                    <div class="col-sm-10">
                                        <input type="password" class="form-control" id="newPassword2"
                                               name="newPassword2"
                                               required>
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <div class="col-sm-10 offset-sm-2">
                                        <button type="submit" class="btn btn-danger form-control">重置密码</button>
                                    </div>
                                </div>
                            </form>

                        </div>
                    </div>
                    <textarea class="form-control" id="code2">
/**
 * 修复方式：验证验证码时间戳是否在有效期内（1分钟内）、验证码长度6位
 */
long currentTime = new Date().getTime();
long timeDifference = currentTime - authCodeTimestamp;
if (timeDifference <= 60000) {
    userPasswords.put(storedMobile, newPassword);
    response.put("message", "密码重置成功！");
}
          </textarea><br><br>
                </div>

            </div>
        </main>
    </div>
</div>

<div th:replace="~{commons/commons::script}"></div>
<script>
    function validateChinesePhoneNumber(phoneNumber) {
        // 使用正则表达式简单验证手机号格式
        const phoneRegex = /^1\d{10}$/; // 以1开头，后面跟着10位数字
        return phoneRegex.test(phoneNumber);
    }

    function sendSms() {
        const phone = document.getElementById("phone").value;
        const button = document.getElementById("getcode");

        if (!validateChinesePhoneNumber(phone)) {
            alert("请输入正确的手机号码");
            return
        }
        if (phone.trim() == "") {
            // 如果手机号不为空，则启用获取验证码按钮
            alert("请先输入手机号");
            return
        }

        button.disabled = true;

        // 模拟发送短信请求
        fetch('/vulnapi/LogicFlaw/PasswordReset/sendcode', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: 'mobile=' + phone
        })
            .then(response => response.json())
            .then(data => {
                alert("验证码已发送到手机，请注意查收！");
                // 开始倒计时
                let timeLeft = 60;
                const countdown = setInterval(function () {
                    if (timeLeft <= 0) {
                        clearInterval(countdown);
                        button.innerText = "获取验证码";
                        button.disabled = false;
                    } else {
                        button.innerText = "重新发送(" + timeLeft + ")";
                        timeLeft--;
                    }
                }, 1000);
            })
            .catch(error => {
                console.error('Error:', error);
                alert("发送失败，请稍后重试！");
            });
    }

    // 密码重置接口
    function resetPassword() {
        const authCode = document.getElementById("authCode").value;
        const newPassword = document.getElementById("newPassword").value;
        const phone = document.getElementById("phone").value;

        fetch('/vulnapi/LogicFlaw/PasswordReset/reset', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: 'code=' + authCode + '&newPassword=' + newPassword + '&mobile=' + phone
        })
            .then(response => response.json())
            .then(data => {
                alert(data.message);
            })
            .catch(error => {
                console.error('Error:', error);
                alert("密码重置失败，请稍后重试！");
            });
    }

    function sendSms2() {
        const phone = document.getElementById("phone2").value;
        const button = document.getElementById("getcode2");
        alert(phone);
        if (!validateChinesePhoneNumber(phone)) {
            alert("请输入正确的手机号码");
            return
        }
        if (phone.trim() == "") {
            // 如果手机号不为空，则启用获取验证码按钮
            alert("请先输入手机号");
            return
        }

        button.disabled = true;

        // 模拟发送短信请求
        fetch('/vulnapi/LogicFlaw/PasswordReset/sendcode2', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: 'mobile=' + phone
        })
            .then(response => response.json())
            .then(data => {
                alert("验证码已发送到手机，请注意查收！");
                // 开始倒计时
                let timeLeft = 60;
                const countdown = setInterval(function () {
                    if (timeLeft <= 0) {
                        clearInterval(countdown);
                        button.innerText = "获取验证码";
                        button.disabled = false;
                    } else {
                        button.innerText = "重新发送(" + timeLeft + ")";
                        timeLeft--;
                    }
                }, 1000);
            })
            .catch(error => {
                console.error('Error:', error);
                alert("发送失败，请稍后重试！");
            });
    }

    function resetPassword2() {
        const authCode = document.getElementById("authCode2").value;
        const newPassword = document.getElementById("newPassword2").value;
        const phone = document.getElementById("phone2").value;

        fetch('/vulnapi/LogicFlaw/PasswordReset/reset2', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: 'code=' + authCode + '&newPassword=' + newPassword + '&mobile=' + phone
        })
            .then(response => response.json())
            .then(data => {
                alert(data.message);
            })
            .catch(error => {
                console.error('Error:', error);
                alert("密码重置失败，请稍后重试！");
            });
    }

</script>
</body>

</html>